/*
* Copyright 2016 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

@testable import Blockly
import XCTest
import AEXML

class BlockXMLTest: XCTestCase {

  // MARK: - Setup

  var factory: BlockFactory!

  override func setUp() {
    factory = BlockFactory()
    BKYAssertDoesNotThrow {
      try factory.load(fromJSONPaths: ["xml_parsing_test.json"], bundle: Bundle(for: type(of: self)))
    }

    super.setUp()
  }

  // MARK: - XML Parsing Tests

  func testParseXML_SimpleBlocks() {
    if let rootBlock = parseBlockFromXML(BlockTestStrings.SIMPLE_BLOCK, factory)?.rootBlock {
      XCTAssertEqual(WorkspacePoint(x: 37, y: 13), rootBlock.position)
      XCTAssertEqual("3", rootBlock.uuid)
      XCTAssertEqual("simple_block",
        (rootBlock.firstField(withName: "text_input") as? FieldInput)?.text)
    } else {
      XCTFail("Block tree was not parsed")
    }

    // All blocks need a type. Ids can be generated by the BlockFactory.
    if let rootBlock = parseBlockFromXML(BlockTestStrings.NO_BLOCK_ID, factory)?.rootBlock {
      XCTAssertEqual(WorkspacePoint(x: -135, y: -902), rootBlock.position)
      XCTAssertEqual("no_block_id",
        (rootBlock.firstField(withName: "text_input") as? FieldInput)?.text)
    } else {
      XCTFail("Block tree was not parsed")
    }
    XCTAssertNil(parseBlockFromXML(BlockTestStrings.NO_BLOCK_TYPE, factory))

    // Only top level blocks need a position.
    XCTAssertNotNil(parseBlockFromXML(BlockTestStrings.NO_BLOCK_POSITION, factory))
  }

  func testParseXML_BlocksWithInputValues() {
    // Values.
    if let blockTree =
      parseBlockFromXML(BlockTestStrings.assembleBlock(BlockTestStrings.VALUE_GOOD), factory)
    {
      XCTAssertEqual(2, blockTree.allBlocks.count)
      let block = blockTree.rootBlock.firstInput(withName: "value_input")?.connectedBlock
      XCTAssertEqual("6", block?.uuid)
    } else {
      XCTFail("Block tree was not parsed")
    }
    // Value: no output connection on child
    XCTAssertNil(parseBlockFromXML(
      BlockTestStrings.assembleBlock(BlockTestStrings.VALUE_NO_OUTPUT), factory))
    // value: null child block
    XCTAssertNil(parseBlockFromXML(
      BlockTestStrings.assembleBlock(BlockTestStrings.VALUE_NO_CHILD), factory))
    // Value: no input with that name
    XCTAssertNil(parseBlockFromXML(
      BlockTestStrings.assembleBlock(BlockTestStrings.VALUE_BAD_NAME), factory))
    // Value: multiple values for the same input
    XCTAssertNil(parseBlockFromXML(
      BlockTestStrings.assembleBlock(BlockTestStrings.VALUE_REPEATED), factory))
  }

  func testParseXML_BlocksWithComments() {
    // Comment: with text
    if let blockTree =
      parseBlockFromXML(BlockTestStrings.assembleBlock(BlockTestStrings.COMMENT_GOOD), factory)
    {
      XCTAssertEqual("Calm", blockTree.rootBlock.comment)
    } else {
      XCTFail("Block tree was not parsed")
    }

    // Comment: empty string
    if let blockTree =
      parseBlockFromXML(BlockTestStrings.assembleBlock(BlockTestStrings.COMMENT_NO_TEXT), factory)
    {
      XCTAssertEqual("", blockTree.rootBlock.comment)
    } else {
      XCTFail("Block tree was not parsed")
    }
  }

  func testParseXML_BlocksWithFields() {
    // Fields
    if let blockTree = parseBlockFromXML(
      BlockTestStrings.assembleBlock(BlockTestStrings.FIELD_HAS_NAME), factory)
    {
      XCTAssertEqual("field_has_name",
        (blockTree.rootBlock.firstField(withName: "text_input") as? FieldInput)?.text)
    } else {
      XCTFail("Block tree was not parsed")
    }
    // A missing or unknown field name isn't an error, it's just ignored.
    XCTAssertNotNil(parseBlockFromXML(
      BlockTestStrings.assembleBlock(BlockTestStrings.FIELD_MISSING_NAME), factory))
    XCTAssertNotNil(parseBlockFromXML(
      BlockTestStrings.assembleBlock(BlockTestStrings.FIELD_UNKNOWN_NAME), factory))
    XCTAssertNotNil(parseBlockFromXML(
      BlockTestStrings.assembleBlock(BlockTestStrings.FIELD_MISSING_TEXT), factory))
  }

  func testParseXML_BlocksWithInputStatements() {
    // Statement
    if let blockTree =
      parseBlockFromXML(BlockTestStrings.assembleBlock(BlockTestStrings.STATEMENT_GOOD), factory)
    {
      XCTAssertEqual(2, blockTree.allBlocks.count)
      let block = blockTree.rootBlock.firstInput(withName: "NAME")?.connectedBlock
      XCTAssertEqual("11", block?.uuid)
    } else {
      XCTFail("Block tree was not parsed")
    }

    // Statement: null child block
    XCTAssertNil(parseBlockFromXML(
      BlockTestStrings.assembleBlock(BlockTestStrings.STATEMENT_NO_CHILD), factory))
    // Statement: no previous connection on child block
    XCTAssertNil(parseBlockFromXML(
      BlockTestStrings.assembleBlock(BlockTestStrings.STATEMENT_BAD_CHILD), factory))
    // Statement: no input with that name
    XCTAssertNil(parseBlockFromXML(
      BlockTestStrings.assembleBlock(BlockTestStrings.STATEMENT_BAD_NAME), factory))
  }

  func testParseXML_BlocksWithNextStatement() {
    let xml = BlockTestStrings.assembleBlock(BlockTestStrings.NEXT_STATEMENT_GOOD)
    if let blockTree = parseBlockFromXML(xml, factory) {
      XCTAssertEqual(2, blockTree.allBlocks.count)
      let block = blockTree.rootBlock.nextBlock
      XCTAssertEqual("11", block?.uuid)
    } else {
      XCTFail("Block tree was not parsed")
    }
  }

  func testParseXML_SimpleShadowBlock() {
    if let blockTree = parseBlockFromXML(BlockTestStrings.SIMPLE_SHADOW, factory) {
      XCTAssertEqual(1, blockTree.allBlocks.count)
      XCTAssertEqual("frankenblock", blockTree.rootBlock.name)
      XCTAssertEqual(WorkspacePoint(x: 37, y: 13), blockTree.rootBlock.position)
      XCTAssertTrue(blockTree.rootBlock.shadow)
    } else {
      XCTFail("Could not load block from XML")
    }
  }

  func testParseXML_BlockWithShadowInputValue() {
    let xml = BlockTestStrings.assembleBlock(BlockTestStrings.VALUE_SHADOW)
    if let blockTree = parseBlockFromXML(xml, factory),
      let connection = blockTree.rootBlock.firstInput(withName: "value_input")?.connection
    {
      XCTAssertEqual(2, blockTree.allBlocks.count)
      XCTAssertFalse(connection.connected)
      XCTAssertTrue(connection.shadowConnected)
    } else {
      XCTFail("Could not load block from XML")
    }
  }

  func testParseXML_BlockWithRealAndShadowInputValues() {
    let xml = BlockTestStrings.assembleBlock(BlockTestStrings.VALUE_SHADOW_GOOD)
    if let blockTree = parseBlockFromXML(xml, factory),
      let connection = blockTree.rootBlock.firstInput(withName: "value_input")?.connection
    {
      XCTAssertEqual(3, blockTree.allBlocks.count)
      XCTAssertTrue(connection.connected)
      XCTAssertEqual("VALUE_REAL", connection.targetBlock?.uuid)
      XCTAssertFalse(connection.targetBlock?.shadow ?? true)
      XCTAssertTrue(connection.shadowConnected)
      XCTAssertEqual("VALUE_SHADOW", connection.shadowBlock?.uuid)
      XCTAssertTrue(connection.shadowBlock?.shadow ?? false)
    } else {
      XCTFail("Could not load block from XML")
    }
  }

  func testParseXML_BlockWithShadowInputStatement() {
    let xml = BlockTestStrings.assembleBlock(BlockTestStrings.STATEMENT_SHADOW_ONLY)
    if let blockTree = parseBlockFromXML(xml, factory),
      let connection = blockTree.rootBlock.firstInput(withName: "NAME")?.connection
    {
      XCTAssertEqual(2, blockTree.allBlocks.count)
      XCTAssertFalse(connection.connected)
      XCTAssertTrue(connection.shadowConnected)
    } else {
      XCTFail("Could not load block from XML")
    }
  }

  func testParseXML_BlockWithRealAndShadowInputStatements() {
    let xml = BlockTestStrings.assembleBlock(BlockTestStrings.STATEMENT_REAL_AND_SHADOW)
    if let blockTree = parseBlockFromXML(xml, factory),
      let connection = blockTree.rootBlock.firstInput(withName: "NAME")?.connection
    {
      XCTAssertTrue(connection.connected)
      XCTAssertEqual("STATEMENT_REAL", connection.targetBlock?.uuid)
      XCTAssertFalse(connection.targetBlock?.shadow ?? true)
      XCTAssertTrue(connection.shadowConnected)
      XCTAssertEqual("STATEMENT_SHADOW", connection.shadowBlock?.uuid)
      XCTAssertTrue(connection.shadowBlock?.shadow ?? false)
    } else {
      XCTFail("Could not load block from XML")
    }
  }

  func testParseXML_BlockWithShadowNextStatement() {
    let xml = BlockTestStrings.assembleBlock(BlockTestStrings.NEXT_STATEMENT_SHADOW_ONLY)
    if let blockTree = parseBlockFromXML(xml, factory),
      let connection = blockTree.rootBlock.nextConnection
    {
      XCTAssertEqual(2, blockTree.allBlocks.count)
      XCTAssertFalse(connection.connected)
      XCTAssertTrue(connection.shadowConnected)
      XCTAssertEqual("STATEMENT_SHADOW", connection.shadowBlock?.uuid)
    } else {
      XCTFail("Could not load block from XML")
    }
  }

  func testParseXML_BlockWithRealAndShadowNextStatements() {
    let xml = BlockTestStrings.assembleBlock(BlockTestStrings.NEXT_STATEMENT_REAL_AND_SHADOW)
    if let blockTree = parseBlockFromXML(xml, factory),
      let connection = blockTree.rootBlock.nextConnection
    {
      XCTAssertTrue(connection.connected)
      XCTAssertEqual("STATEMENT_REAL", connection.targetBlock?.uuid)
      XCTAssertFalse(connection.targetBlock?.shadow ?? true)
      XCTAssertTrue(connection.shadowConnected)
      XCTAssertEqual("STATEMENT_SHADOW", connection.shadowBlock?.uuid)
      XCTAssertTrue(connection.shadowBlock?.shadow ?? false)
    } else {
      XCTFail("Could not load block from XML")
    }
  }

  func testParseXML_BlockWithValidNestedShadowBlocks() {
    let xml = BlockTestStrings.assembleBlock(BlockTestStrings.NESTED_SHADOW_GOOD)
    if let blockTree = parseBlockFromXML(xml, factory),
      let connection = blockTree.rootBlock.firstInput(withName: "value_input")?.connection,
      let nextConnection = blockTree.rootBlock.nextConnection
    {
      XCTAssertFalse(connection.connected)
      XCTAssertTrue(connection.shadowConnected)
      XCTAssertEqual("SHADOW1", connection.shadowBlock?.uuid)

      if let nestedInput = connection.shadowBlock?.onlyValueInput() {
        XCTAssertNil(nestedInput.connectedBlock)
        XCTAssertNotNil(nestedInput.connectedShadowBlock)
        XCTAssertEqual("SHADOW2", nestedInput.connectedShadowBlock?.uuid)
      } else {
        XCTFail("Could not locate nested input")
      }

      XCTAssertFalse(nextConnection.connected)
      XCTAssertTrue(nextConnection.shadowConnected)
      XCTAssertEqual("SHADOW3", nextConnection.shadowBlock?.uuid)
    } else {
      XCTFail("Could not load block from XML")
    }
  }

  func testParseXML_BlockWithInvalidNestedShadowBlocks() {
    let xml = BlockTestStrings.assembleBlock(BlockTestStrings.NESTED_SHADOW_BAD)
    XCTAssertNil(parseBlockFromXML(xml, factory))
  }

  func testParseXML_BlockWithMutator() {
    // Add DummyMutator to "frankenblock" factory builder
    factory.blockBuilder(forName: "frankenblock")?.extensions = [BlockExtensionClosure { block in
      self.BKYAssertDoesNotThrow {
        try block.setMutator(DummyMutator())
      }
    }]

    // Parse block with mutation xml
    let xml = BlockTestStrings.assembleBlock(BlockTestStrings.DUMMY_MUTATOR_VALUE)
    let block = parseBlockFromXML(xml, factory)

    XCTAssertNotNil(block?.rootBlock)
    XCTAssertEqual("dummy_mutator_xml_id", (block?.rootBlock.mutator as? DummyMutator)?.id)
  }

  func testParseXML_BlockDeletableTrue() throws {
    if let rootBlock =
      parseBlockFromXML(BlockTestStrings.BLOCK_DELETABLE_TRUE, factory)?.rootBlock {
      XCTAssertEqual(true, rootBlock.deletable)
    } else {
      XCTFail("Block tree was not parsed")
    }
  }

  func testParseXML_BlockDeletableFalse() throws {
    if let rootBlock =
      parseBlockFromXML(BlockTestStrings.BLOCK_DELETABLE_FALSE, factory)?.rootBlock {
      XCTAssertEqual(false, rootBlock.deletable)
    } else {
      XCTFail("Block tree was not parsed")
    }
  }

  func testParseXML_BlockMovableTrue() throws {
    if let rootBlock = parseBlockFromXML(BlockTestStrings.BLOCK_MOVABLE_TRUE, factory)?.rootBlock {
      XCTAssertEqual(true, rootBlock.movable)
    } else {
      XCTFail("Block tree was not parsed")
    }
  }

  func testParseXML_BlockMovableFalse() throws {
    if let rootBlock =
      parseBlockFromXML(BlockTestStrings.BLOCK_MOVABLE_FALSE, factory)?.rootBlock {
      XCTAssertEqual(false, rootBlock.movable)
    } else {
      XCTFail("Block tree was not parsed")
    }
  }

  func testParseXML_BlockEditableTrue() throws {
    if let rootBlock =
      parseBlockFromXML(BlockTestStrings.BLOCK_EDITABLE_TRUE, factory)?.rootBlock {
      XCTAssertEqual(true, rootBlock.editable)
    } else {
      XCTFail("Block tree was not parsed")
    }
  }

  func testParseXML_BlockEditableFalse() throws {
    if let rootBlock =
      parseBlockFromXML(BlockTestStrings.BLOCK_EDITABLE_FALSE, factory)?.rootBlock {
      XCTAssertEqual(false, rootBlock.editable)
    } else {
      XCTFail("Block tree was not parsed")
    }
  }

  func testParseXML_BlockDisabledTrue() throws {
    if let rootBlock =
      parseBlockFromXML(BlockTestStrings.BLOCK_DISABLED_TRUE, factory)?.rootBlock {
      XCTAssertEqual(true, rootBlock.disabled)
    } else {
      XCTFail("Block tree was not parsed")
    }
  }

  func testParseXML_BlockDisabledFalse() throws {
    if let rootBlock =
      parseBlockFromXML(BlockTestStrings.BLOCK_DISABLED_FALSE, factory)?.rootBlock {
      XCTAssertEqual(false, rootBlock.disabled)
    } else {
      XCTFail("Block tree was not parsed")
    }
  }

  // MARK: - XML Serialization Tests

  func testSerializeXML_SimpleBlockWithPosition() {
    let block = BKYAssertDoesNotThrow {
      try factory.makeBlock(name: "empty_block", shadow: false, uuid: "block_uuid")
    }
    block?.position = WorkspacePoint(x: 999, y: -111)

    // This is the xml we expect from `block`:
    // <block type=\"empty_block\" id=\"block_uuid\" x=\"37\" y=\"13\" />
    let xml = try! block?.toXMLElement()
    XCTAssertEqual("block", xml?.name)
    XCTAssertEqual(4, xml?.attributes.count)
    XCTAssertEqual("block_uuid", xml?.attributes["id"])
    XCTAssertEqual("999", xml?.attributes["x"])
    XCTAssertEqual("-111", xml?.attributes["y"])
    XCTAssertEqual("empty_block", xml?.attributes["type"])
    XCTAssertEqual(0, xml?.children.count)
  }

  func testSerializeXML_SimpleBlockWithNoPosition() {
    let block = BKYAssertDoesNotThrow {
      try factory.makeBlock(name: "empty_block", shadow: false, uuid: "uuid")
    }

    // This is the xml we expect from `block`:
    // <block type=\"empty_block\" id=\"uuid\" x=\"0\" y=\"0\" />
    let xml = try! block?.toXMLElement()
    XCTAssertEqual("block", xml?.name)
    XCTAssertEqual(4, xml?.attributes.count)
    XCTAssertEqual("uuid", xml?.attributes["id"])
    XCTAssertEqual("0", xml?.attributes["x"])
    XCTAssertEqual("0", xml?.attributes["y"])
    XCTAssertEqual("empty_block", xml?.attributes["type"])
    XCTAssertEqual(0, xml?.children.count)
  }

  func testSerializeXML_BlockWithInputValue() {
    guard
      let block = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(name: "frankenblock", shadow: false, uuid: "364")
      }),
      let input = BKYAssertDoesNotThrow({
        block.firstInput(withName: "value_input")
      }),
      let inputBlock = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(name: "output_foo", shadow: false, uuid: "126")
      }) else
    {
      XCTFail("Could not build blocks")
      return
    }
    BKYAssertDoesNotThrow { try input.connection?.connectTo(inputBlock.inferiorConnection) }

    block.position = WorkspacePoint(x: 37, y: 13)

    // This is the xml we expect from `block`:
    // <block id="364" x="37" y="13" type="frankenblock">
    //   <value name="value_input">
    //     <block id="126" type="output_foo" />
    //   </value>
    //   <field name="text_input">something</field>
    //   <field name="checkbox">true</field>
    // </block>

    let xml = try! block.toXMLElement()

    // Test: <block id="364" x="37" y="13" type="frankenblock">
    XCTAssertEqual("block", xml.name)
    XCTAssertEqual(4, xml.attributes.count)
    XCTAssertEqual("364", xml.attributes["id"])
    XCTAssertEqual("37", xml.attributes["x"])
    XCTAssertEqual("13", xml.attributes["y"])
    XCTAssertEqual("frankenblock", xml.attributes["type"])
    XCTAssertEqual(7, xml.children.count)

    // Test:
    // <value name="value_input">
    //   <block id="126" type="output_foo" />
    // </value>
    if xml.children.count >= 1 {
      let valueXML = xml.children[0]
      XCTAssertEqual("value", valueXML.name)
      XCTAssertEqual(1, valueXML.attributes.count)
      XCTAssertEqual("value_input", valueXML.attributes["name"])
      XCTAssertEqual(1, valueXML.children.count)

      if valueXML.children.count > 0 {
        let subBlock = valueXML.children[0]
        XCTAssertEqual("block", subBlock.name)
        XCTAssertEqual(2, subBlock.attributes.count)
        XCTAssertEqual("126", subBlock.attributes["id"])
        XCTAssertEqual("output_foo", subBlock.attributes["type"])
        XCTAssertEqual(0, subBlock.children.count)
      }
    }

    // Test: <field name="text_input">something</field>
    if xml.children.count >= 2 {
      let fieldXML = xml.children[1]
      XCTAssertEqual("field", fieldXML.name)
      XCTAssertEqual(1, fieldXML.attributes.count)
      XCTAssertEqual("text_input", fieldXML.attributes["name"])
      XCTAssertEqual("something", fieldXML.value)
      XCTAssertEqual(0, fieldXML.children.count)
    }

    // Test: <field name="checkbox">true</field>
    if xml.children.count >= 3 {
      let fieldXML = xml.children[2]
      XCTAssertEqual("field", fieldXML.name)
      XCTAssertEqual(1, fieldXML.attributes.count)
      XCTAssertEqual("checkbox", fieldXML.attributes["name"])
      XCTAssertEqual("TRUE", fieldXML.value)
      XCTAssertEqual(0, fieldXML.children.count)
    }
  }

  func testSerializeXML_BlockWithInputStatement() {
    guard
      let block = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(name: "frankenblock", shadow: false, uuid: "1000")
      }),
      let input = BKYAssertDoesNotThrow({
        block.firstInput(withName: "NAME")
      }),
      let inputBlock = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(name: "statement_no_input", shadow: false, uuid: "2000")
      }) else
    {
      XCTFail("Could not build blocks")
      return
    }
    BKYAssertDoesNotThrow { try input.connection?.connectTo(inputBlock.inferiorConnection) }

    block.position = WorkspacePoint(x: -350, y: -32)

    // This is the xml we expect from `block`:
    // <block type="frankenblock" id="1000" x="0" y="0">
    //   <field name="text_input">something</field>
    //   <field name="checkbox">true</field>
    //   <statement name="NAME">
    //     <block type="statement_no_input" id="2000" />
    //   </statement>
    //   <field name="dropdown">OPTIONNAME1</field>
    //   <field name="variable">item</field>
    //   <field name="angle">90</field>
    //   <field name="colour">#ff0000</field>
    // </block>

    let xml = try! block.toXMLElement()

    // Test: <block type="frankenblock" id="1000" x="0" y="0">
    XCTAssertEqual("block", xml.name)
    XCTAssertEqual(4, xml.attributes.count)
    XCTAssertEqual("1000", xml.attributes["id"])
    XCTAssertEqual("-350", xml.attributes["x"])
    XCTAssertEqual("-32", xml.attributes["y"])
    XCTAssertEqual("frankenblock", xml.attributes["type"])
    XCTAssertEqual(7, xml.children.count)

    // Test: <field name="text_input">something</field>
    if xml.children.count >= 1 {
      let fieldXML = xml.children[0]
      XCTAssertEqual("field", fieldXML.name)
      XCTAssertEqual(1, fieldXML.attributes.count)
      XCTAssertEqual("text_input", fieldXML.attributes["name"])
      XCTAssertEqual("something", fieldXML.value)
      XCTAssertEqual(0, fieldXML.children.count)
    }

    // Test: <field name="checkbox">true</field>
    if xml.children.count >= 2 {
      let fieldXML = xml.children[1]
      XCTAssertEqual("field", fieldXML.name)
      XCTAssertEqual(1, fieldXML.attributes.count)
      XCTAssertEqual("checkbox", fieldXML.attributes["name"])
      XCTAssertEqual("TRUE", fieldXML.value)
      XCTAssertEqual(0, fieldXML.children.count)
    }

    // Test:
    // <statement name="NAME">
    //   <block type="statement_no_input" id="2000" />
    // </statement>
    if xml.children.count >= 3 {
      let statementXML = xml.children[2]
      XCTAssertEqual("statement", statementXML.name)
      XCTAssertEqual(1, statementXML.attributes.count)
      XCTAssertEqual("NAME", statementXML.attributes["name"])
      XCTAssertEqual(1, statementXML.children.count)

      if statementXML.children.count > 0 {
        let subBlock = statementXML.children[0]
        XCTAssertEqual("block", subBlock.name)
        XCTAssertEqual(2, subBlock.attributes.count)
        XCTAssertEqual("2000", subBlock.attributes["id"])
        XCTAssertEqual("statement_no_input", subBlock.attributes["type"])
        XCTAssertEqual(0, subBlock.children.count)
      }
    }

    // Test: <field name="dropdown">OPTIONNAME1</field>
    if xml.children.count >= 4 {
      let fieldXML = xml.children[3]
      XCTAssertEqual("field", fieldXML.name)
      XCTAssertEqual(1, fieldXML.attributes.count)
      XCTAssertEqual("dropdown", fieldXML.attributes["name"])
      XCTAssertEqual("OPTIONNAME1", fieldXML.value)
      XCTAssertEqual(0, fieldXML.children.count)
    }

    // Test: <field name="variable">item</field>
    if xml.children.count >= 5 {
      let fieldXML = xml.children[4]
      XCTAssertEqual("field", fieldXML.name)
      XCTAssertEqual(1, fieldXML.attributes.count)
      XCTAssertEqual("variable", fieldXML.attributes["name"])
      XCTAssertEqual("item", fieldXML.value)
      XCTAssertEqual(0, fieldXML.children.count)
    }

    // Test: <field name="angle">90</field>
    if xml.children.count >= 6 {
      let fieldXML = xml.children[5]
      XCTAssertEqual("field", fieldXML.name)
      XCTAssertEqual(1, fieldXML.attributes.count)
      XCTAssertEqual("angle", fieldXML.attributes["name"])
      XCTAssertEqual("90", fieldXML.value)
      XCTAssertEqual(0, fieldXML.children.count)
    }

    // Test: <field name="colour">#ff0000</field>
    if xml.children.count >= 7 {
      let fieldXML = xml.children[6]
      XCTAssertEqual("field", fieldXML.name)
      XCTAssertEqual(1, fieldXML.attributes.count)
      XCTAssertEqual("colour", fieldXML.attributes["name"])
      XCTAssertEqual("#ff0000", fieldXML.value)
      XCTAssertEqual(0, fieldXML.children.count)
    }
  }

  func testSerializeXML_BlockWithNextStatement() {
    guard
      let block = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(name: "statement_no_input", shadow: false, uuid: "1000")
      }),
      let nextBlock = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(name: "statement_no_input", shadow: false, uuid: "2000")
      }) else
    {
      XCTFail("Could not build blocks")
      return
    }
    block.position = WorkspacePoint(x: -350, y: -32)
    nextBlock.position = WorkspacePoint(x: 100, y: 50)

    BKYAssertDoesNotThrow { () -> Void in
      try block.nextConnection?.connectTo(nextBlock.previousConnection)
    }

    // This is the xml we expect from `block`:
    // <block type="statement_no_input" id="1000" x="-350" y="-32">
    //   <next>
    //     <block type="statement_no_input" id="2000" />
    //   </next>
    // </block>

    guard let xml = BKYAssertDoesNotThrow({ try block.toXMLElement() }) else {
      XCTFail("Could not build XML")
      return
    }

    // Test: <block type="statement_no_input" id="1000" x="-350" y="-32">
    XCTAssertEqual("block", xml.name)
    XCTAssertEqual(4, xml.attributes.count)
    XCTAssertEqual("1000", xml.attributes["id"])
    XCTAssertEqual("-350", xml.attributes["x"])
    XCTAssertEqual("-32", xml.attributes["y"])
    XCTAssertEqual("statement_no_input", xml.attributes["type"])
    XCTAssertEqual(1, xml.children.count)

    // Test: <next>
    if xml.children.count >= 1 {
      let nextXML = xml.children[0]
      XCTAssertEqual("next", nextXML.name)
      XCTAssertEqual(0, nextXML.attributes.count)
      XCTAssertEqual(1, nextXML.children.count)

      // Test: <block type="statement_no_input" id="2000" />
      if nextXML.children.count >= 1 {
        let childXML = nextXML.children[0]
        XCTAssertEqual("block", childXML.name)
        XCTAssertEqual(2, childXML.attributes.count)
        XCTAssertEqual("statement_no_input", childXML.attributes["type"])
        XCTAssertEqual("2000", childXML.attributes["id"])
        XCTAssertEqual(0, childXML.children.count)
      }
    }
  }

  func testSerializeXML_ShadowBlock() {
    guard let block = BKYAssertDoesNotThrow(
      { try self.factory.makeBlock(name: "empty_block", shadow: true, uuid: "abc") }) else
    {
      XCTFail("Could not build block")
      return
    }
    block.position = WorkspacePoint(x: 350, y: -10)

    // This is the xml we expect from `block`:
    // <shadow type=\"empty_block\" id=\"abc\" x=\"350\" y=\"-10\" />

    guard let xml = BKYAssertDoesNotThrow({ try block.toXMLElement() }) else {
      XCTFail("Could not serialize block into XML")
      return
    }

    XCTAssertEqual("shadow", xml.name)
    XCTAssertEqual(4, xml.attributes.count)
    XCTAssertEqual("abc", xml.attributes["id"])
    XCTAssertEqual("350", xml.attributes["x"])
    XCTAssertEqual("-10", xml.attributes["y"])
    XCTAssertEqual("empty_block", xml.attributes["type"])
    XCTAssertEqual(0, xml.children.count)
  }

  func testSerializeXML_BlockWithShadowInputValue() {
    guard
      let block = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(name: "simple_input_output", shadow: false, uuid: "364")
      }),
      let shadowBlock = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(name: "output_foo", shadow: true, uuid: "VALUE_SHADOW")
      }) else
    {
      XCTFail("Could not build blocks")
      return
    }
    block.position = WorkspacePoint(x: 37, y: 13)

    BKYAssertDoesNotThrow { () -> Void in
      let input = block.firstInput(withName: "value")
      try input?.connection?.connectShadowTo(shadowBlock.outputConnection)
    }

    // This is the xml we expect from `block`:
    // <block x="37" id="364" y="13" type="simple_input_output">
    //   <value name="value">
    //     <shadow id="VALUE_SHADOW" type="output_foo" />
    //   </value>
    // </block>

    guard let xml = BKYAssertDoesNotThrow({ try block.toXMLElement() }) else {
      XCTFail("Could not serialize block into XML")
      return
    }

    // Test: <block x="37" id="364" y="13" type="simple_input_output">
    XCTAssertEqual("block", xml.name)
    XCTAssertEqual(4, xml.attributes.count)
    XCTAssertEqual("364", xml.attributes["id"])
    XCTAssertEqual("37", xml.attributes["x"])
    XCTAssertEqual("13", xml.attributes["y"])
    XCTAssertEqual("simple_input_output", xml.attributes["type"])
    XCTAssertEqual(1, xml.children.count)

    if xml.children.count >= 1 {
      // Test: <value name="value">
      let valueXML = xml.children[0]
      XCTAssertEqual("value", valueXML.name)
      XCTAssertEqual(1, valueXML.attributes.count)
      XCTAssertEqual("value", valueXML.attributes["name"])
      XCTAssertEqual(1, valueXML.children.count)

      // Test: <shadow id="VALUE_SHADOW" type="output_foo" />
      if valueXML.children.count >= 0 {
        let shadowBlockXML = valueXML.children[0]
        XCTAssertEqual("shadow", shadowBlockXML.name)
        XCTAssertEqual(2, shadowBlockXML.attributes.count)
        XCTAssertEqual("VALUE_SHADOW", shadowBlockXML.attributes["id"])
        XCTAssertEqual("output_foo", shadowBlockXML.attributes["type"])
        XCTAssertEqual(0, shadowBlockXML.children.count)
      }
    }
  }

  func testSerializeXML_BlockWithRealAndShadowInputValues() {
    guard let block = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(name: "simple_input_output", shadow: false, uuid: "364")
      }),
      let realBlock = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(name: "output_foo", shadow: false, uuid: "VALUE_REAL")
      }),
      let shadowBlock = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(name: "output_foo", shadow: true, uuid: "VALUE_SHADOW")
      }) else
    {
      XCTFail("Could not build blocks")
      return
    }
    block.position = WorkspacePoint(x: 37, y: 13)

    BKYAssertDoesNotThrow { () -> Void in
      let input = block.firstInput(withName: "value")
      try input?.connection?.connectTo(realBlock.outputConnection)
      try input?.connection?.connectShadowTo(shadowBlock.outputConnection)
    }

    // This is the xml we expect from `block`:
    // <block x="37" id="364" y="13" type="simple_input_output">
    //   <value name="value">
    //     <block id="VALUE_REAL" type="output_foo" />
    //     <shadow id="VALUE_SHADOW" type="output_foo" />
    //   </value>
    // </block>

    guard let xml = BKYAssertDoesNotThrow({ try block.toXMLElement() }) else {
      XCTFail("Could not serialize block into XML")
      return
    }

    // Test: <block x="37" id="364" y="13" type="simple_input_output">
    XCTAssertEqual("block", xml.name)
    XCTAssertEqual(4, xml.attributes.count)
    XCTAssertEqual("364", xml.attributes["id"])
    XCTAssertEqual("37", xml.attributes["x"])
    XCTAssertEqual("13", xml.attributes["y"])
    XCTAssertEqual("simple_input_output", xml.attributes["type"])
    XCTAssertEqual(1, xml.children.count)

    if xml.children.count >= 1 {
      // Test: <value name="value">
      let valueXML = xml.children[0]
      XCTAssertEqual("value", valueXML.name)
      XCTAssertEqual(1, valueXML.attributes.count)
      XCTAssertEqual("value", valueXML.attributes["name"])
      XCTAssertEqual(2, valueXML.children.count)

      // Test: <block id="VALUE_REAL" type="output_foo" />
      if valueXML.children.count >= 1 {
        let realBlockXML = valueXML.children[0]
        XCTAssertEqual("block", realBlockXML.name)
        XCTAssertEqual(2, realBlockXML.attributes.count)
        XCTAssertEqual("VALUE_REAL", realBlockXML.attributes["id"])
        XCTAssertEqual("output_foo", realBlockXML.attributes["type"])
        XCTAssertEqual(0, realBlockXML.children.count)
      }

      // Test: <shadow id="VALUE_SHADOW" type="output_foo" />
      if valueXML.children.count >= 2 {
        let shadowBlockXML = valueXML.children[1]
        XCTAssertEqual("shadow", shadowBlockXML.name)
        XCTAssertEqual(2, shadowBlockXML.attributes.count)
        XCTAssertEqual("VALUE_SHADOW", shadowBlockXML.attributes["id"])
        XCTAssertEqual("output_foo", shadowBlockXML.attributes["type"])
        XCTAssertEqual(0, shadowBlockXML.children.count)
      }
    }
  }

  func testSerializeXML_BlockWithShadowInputStatement() {
    guard
      let block = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(name: "statement_statement_input", shadow: false, uuid: "1000")
      }),
      let shadowBlock = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(name: "statement_no_input", shadow: true, uuid: "2000")
      }) else
    {
      XCTFail("Could not build blocks")
      return
    }
    block.position = WorkspacePoint(x: -350, y: -32)
    shadowBlock.position = WorkspacePoint(x: 100, y: 50)

    BKYAssertDoesNotThrow { () -> Void in
      try block.firstInput(withName: "statement input")?.connection?
        .connectShadowTo(shadowBlock.previousConnection)
    }

    // This is the xml we expect from `block`:
    // <block type="statement_statement_input" id="1000" x="-350" y="-32">
    //   <statement name="statement input">
    //     <shadow type="statement_no_input" id="2000" />
    //   </statement>
    // </block>

    guard let xml = BKYAssertDoesNotThrow({ try block.toXMLElement() }) else {
      XCTFail("Could not build XML")
      return
    }

    // Test: <block type="statement_statement_input" id="1000" x="-350" y="-32">
    XCTAssertEqual("block", xml.name)
    XCTAssertEqual(4, xml.attributes.count)
    XCTAssertEqual("1000", xml.attributes["id"])
    XCTAssertEqual("-350", xml.attributes["x"])
    XCTAssertEqual("-32", xml.attributes["y"])
    XCTAssertEqual("statement_statement_input", xml.attributes["type"])
    XCTAssertEqual(1, xml.children.count)

    // Test: <statement name="statement input">
    if xml.children.count >= 1 {
      let statementXML = xml.children[0]
      XCTAssertEqual("statement", statementXML.name)
      XCTAssertEqual(1, statementXML.attributes.count)
      XCTAssertEqual("statement input", statementXML.attributes["name"])
      XCTAssertEqual(1, statementXML.children.count)

      // Test: <shadow type="statement_no_input" id="2000" />
      if statementXML.children.count >= 1 {
        let childXML = statementXML.children[0]
        XCTAssertEqual("shadow", childXML.name)
        XCTAssertEqual(2, childXML.attributes.count)
        XCTAssertEqual("statement_no_input", childXML.attributes["type"])
        XCTAssertEqual("2000", childXML.attributes["id"])
        XCTAssertEqual(0, childXML.children.count)
      }
    }
  }

  func testSerializeXML_BlockWithRealAndShadowInputStatements() {
    guard
      let block = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(name: "statement_statement_input", shadow: false, uuid: "1000")
      }),
      let realBlock = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(name: "statement_no_input", shadow: false, uuid: "2000")
      }),
      let shadowBlock = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(name: "statement_no_input", shadow: true, uuid: "3000")
      }) else
    {
      XCTFail("Could not build blocks")
      return
    }
    block.position = WorkspacePoint(x: -350, y: -32)
    realBlock.position = WorkspacePoint(x: 20, y: 20)
    shadowBlock.position = WorkspacePoint(x: 100, y: 50)

    BKYAssertDoesNotThrow { () -> Void in
      let input = block.firstInput(withName: "statement input")
      try input?.connection?.connectTo(realBlock.previousConnection)
      try input?.connection?.connectShadowTo(shadowBlock.previousConnection)
    }

    // This is the xml we expect from `block`:
    // <block type="statement_statement_input" id="1000" x="-350" y="-32">
    //   <statement name="statement input">
    //     <block type="statement_no_input" id="2000" />
    //     <shadow type="statement_no_input" id="3000" />
    //   </statement>
    // </block>

    guard let xml = BKYAssertDoesNotThrow({ try block.toXMLElement() }) else {
      XCTFail("Could not build XML")
      return
    }

    // Test: <block type="statement_statement_input" id="1000" x="-350" y="-32">
    XCTAssertEqual("block", xml.name)
    XCTAssertEqual(4, xml.attributes.count)
    XCTAssertEqual("1000", xml.attributes["id"])
    XCTAssertEqual("-350", xml.attributes["x"])
    XCTAssertEqual("-32", xml.attributes["y"])
    XCTAssertEqual("statement_statement_input", xml.attributes["type"])
    XCTAssertEqual(1, xml.children.count)

    // Test: <statement name="statement input">
    if xml.children.count >= 1 {
      let statementXML = xml.children[0]
      XCTAssertEqual("statement", statementXML.name)
      XCTAssertEqual(1, statementXML.attributes.count)
      XCTAssertEqual("statement input", statementXML.attributes["name"])
      XCTAssertEqual(2, statementXML.children.count)

      // Test: <block type="statement_no_input" id="2000" />
      if statementXML.children.count >= 1 {
        let realXML = statementXML.children[0]
        XCTAssertEqual("block", realXML.name)
        XCTAssertEqual(2, realXML.attributes.count)
        XCTAssertEqual("statement_no_input", realXML.attributes["type"])
        XCTAssertEqual("2000", realXML.attributes["id"])
        XCTAssertEqual(0, realXML.children.count)
      }

      // Test: <shadow type="statement_no_input" id="3000" />
      if statementXML.children.count >= 2 {
        let shadowXML = statementXML.children[1]
        XCTAssertEqual("shadow", shadowXML.name)
        XCTAssertEqual(2, shadowXML.attributes.count)
        XCTAssertEqual("statement_no_input", shadowXML.attributes["type"])
        XCTAssertEqual("3000", shadowXML.attributes["id"])
        XCTAssertEqual(0, shadowXML.children.count)
      }
    }
  }

  func testSerializeXML_BlockWithShadowNextStatement() {
    guard
      let block = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(name: "statement_no_input", shadow: false, uuid: "364")
      }),
      let shadowBlock = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(name: "statement_no_next", shadow: true, uuid: "VALUE_SHADOW")
      }) else
    {
      XCTFail("Could not build blocks")
      return
    }
    block.position = WorkspacePoint(x: 37, y: 13)

    BKYAssertDoesNotThrow { () -> Void in
      try block.nextConnection?.connectShadowTo(shadowBlock.previousConnection)
    }

    // This is the xml we expect from `block`:
    // <block id="364" x="37" y="13" type="statement_no_input">
    //   <next>
    //     <shadow id="VALUE_SHADOW" type="statement_no_next" />
    //   </next>
    // </block>

    guard let xml = BKYAssertDoesNotThrow({ try block.toXMLElement() }) else {
      XCTFail("Could not serialize block into XML")
      return
    }

    // Test: <block id="364" x="37" y="13" type="statement_no_input">
    XCTAssertEqual("block", xml.name)
    XCTAssertEqual(4, xml.attributes.count)
    XCTAssertEqual("364", xml.attributes["id"])
    XCTAssertEqual("37", xml.attributes["x"])
    XCTAssertEqual("13", xml.attributes["y"])
    XCTAssertEqual("statement_no_input", xml.attributes["type"])
    XCTAssertEqual(1, xml.children.count)

    if xml.children.count >= 1 {
      // Test: <next>
      let nextXML = xml.children[0]
      XCTAssertEqual("next", nextXML.name)
      XCTAssertEqual(0, nextXML.attributes.count)
      XCTAssertEqual(1, nextXML.children.count)

      // Test: <shadow id="VALUE_SHADOW" type="statement_no_next" />
      if nextXML.children.count >= 1 {
        let shadowBlockXML = nextXML.children[0]
        XCTAssertEqual("shadow", shadowBlockXML.name)
        XCTAssertEqual(2, shadowBlockXML.attributes.count)
        XCTAssertEqual("VALUE_SHADOW", shadowBlockXML.attributes["id"])
        XCTAssertEqual("statement_no_next", shadowBlockXML.attributes["type"])
        XCTAssertEqual(0, shadowBlockXML.children.count)
      }
    }
  }

  func testSerializeXML_BlockWithRealAndShadowNextStatements() {
    guard let block = BKYAssertDoesNotThrow({
      try self.factory.makeBlock(name: "statement_no_input", shadow: false, uuid: "364")
    }),
      let realBlock = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(
          name: "statement_input_no_next", shadow: false, uuid: "VALUE_REAL")
      }),
      let shadowBlock = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(name: "statement_no_next", shadow: true, uuid: "VALUE_SHADOW")
      }) else
    {
      XCTFail("Could not build blocks")
      return
    }
    block.position = WorkspacePoint(x: 37, y: 13)

    BKYAssertDoesNotThrow { () -> Void in
      try block.nextConnection?.connectTo(realBlock.previousConnection)
      try block.nextConnection?.connectShadowTo(shadowBlock.previousConnection)
    }

    // This is the xml we expect from `block`:
    // <block id="364" x="37" y="13" type="statement_no_input">
    //   <next>
    //     <block id="VALUE_REAL" type="statement_input_no_next" />
    //     <shadow id="VALUE_SHADOW" type="statement_no_next" />
    //   </next>
    // </block>

    guard let xml = BKYAssertDoesNotThrow({ try block.toXMLElement() }) else {
      XCTFail("Could not serialize block into XML")
      return
    }

    // Test: <block id="364" x="37" y="13" type="statement_no_input">
    XCTAssertEqual("block", xml.name)
    XCTAssertEqual(4, xml.attributes.count)
    XCTAssertEqual("364", xml.attributes["id"])
    XCTAssertEqual("37", xml.attributes["x"])
    XCTAssertEqual("13", xml.attributes["y"])
    XCTAssertEqual("statement_no_input", xml.attributes["type"])
    XCTAssertEqual(1, xml.children.count)

    if xml.children.count >= 1 {
      // Test: <next>
      let nextXML = xml.children[0]
      XCTAssertEqual("next", nextXML.name)
      XCTAssertEqual(0, nextXML.attributes.count)
      XCTAssertEqual(2, nextXML.children.count)

      // Test: <block id="VALUE_REAL" type="statement_input_no_next" />
      if nextXML.children.count >= 1 {
        let realBlockXML = nextXML.children[0]
        XCTAssertEqual("block", realBlockXML.name)
        XCTAssertEqual(2, realBlockXML.attributes.count)
        XCTAssertEqual("VALUE_REAL", realBlockXML.attributes["id"])
        XCTAssertEqual("statement_input_no_next", realBlockXML.attributes["type"])
        XCTAssertEqual(0, realBlockXML.children.count)
      }

      // Test: <shadow id="VALUE_SHADOW" type="statement_no_next" />
      if nextXML.children.count >= 2 {
        let shadowBlockXML = nextXML.children[1]
        XCTAssertEqual("shadow", shadowBlockXML.name)
        XCTAssertEqual(2, shadowBlockXML.attributes.count)
        XCTAssertEqual("VALUE_SHADOW", shadowBlockXML.attributes["id"])
        XCTAssertEqual("statement_no_next", shadowBlockXML.attributes["type"])
        XCTAssertEqual(0, shadowBlockXML.children.count)
      }
    }
  }

  func testSerializeXML_BlockWithNestedShadowBlocks() {
    guard
      let block = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(
          name: "statement_multiple_value_input", shadow: false, uuid: "777")
      }),
      let parentValueShadowBlock = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(
          name: "simple_input_output", shadow: true, uuid: "SHADOW_VALUE1")
      }),
      let childValueShadowBlock = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(name: "output_foo", shadow: true, uuid: "SHADOW_VALUE2")
      }),
      let parentNextShadowBlock = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(
          name: "statement_no_input", shadow: true, uuid: "SHADOW_STATEMENT1")
      }),
      let childNextShadowBlock = BKYAssertDoesNotThrow({
        try self.factory.makeBlock(
          name: "statement_no_next", shadow: true, uuid: "SHADOW_STATEMENT2")
      }) else
    {
      XCTFail("Could not build blocks")
      return
    }

    block.position = WorkspacePoint(x: 37, y: 13)

    // Connect the blocks together
    BKYAssertDoesNotThrow { () -> Void in
      try block.firstInput(withName: "value_1")?.connection?
        .connectShadowTo(parentValueShadowBlock.outputConnection)
      try parentValueShadowBlock.onlyValueInput()?.connection?
        .connectShadowTo(childValueShadowBlock.outputConnection)

      try block.nextConnection?.connectShadowTo(parentNextShadowBlock.previousConnection)
      try parentNextShadowBlock.nextConnection?
        .connectShadowTo(childNextShadowBlock.previousConnection)
    }

    // This is the xml we expect from `block`:
    // <block x="37" id="777" y="13" type="statement_multiple_value_input">
    //   <value name="value_1">
    //     <shadow id="SHADOW_VALUE1" type="simple_input_output">
    //       <value name="value">
    //         <shadow id="SHADOW_VALUE2" type="output_foo" />
    //       </value>
    //     </shadow>
    //   </value>
    //   <next>
    //     <shadow id="SHADOW_STATEMENT1" type="statement_no_input">
    //       <next>
    //         <shadow id="SHADOW_STATEMENT2" type="statement_no_next" />
    //       </next>
    //     </shadow>
    //   </next>
    // </block>

    guard let xml = BKYAssertDoesNotThrow({ try block.toXMLElement() }) else {
      XCTFail("Could not serialize block into XML")
      return
    }

    // Test: <block x="37" id="777" y="13" type="statement_multiple_value_input">
    XCTAssertEqual("block", xml.name)
    XCTAssertEqual(4, xml.attributes.count)
    XCTAssertEqual("777", xml.attributes["id"])
    XCTAssertEqual("37", xml.attributes["x"])
    XCTAssertEqual("13", xml.attributes["y"])
    XCTAssertEqual("statement_multiple_value_input", xml.attributes["type"])
    XCTAssertEqual(2, xml.children.count)

    if xml.children.count >= 1 {
      // Test: <value name="value_1">
      let valueXML = xml.children[0]
      XCTAssertEqual("value", valueXML.name)
      XCTAssertEqual(1, valueXML.attributes.count)
      XCTAssertEqual("value_1", valueXML.attributes["name"])
      XCTAssertEqual(1, valueXML.children.count)

      // Test: <shadow id="SHADOW_VALUE1" type="simple_input_output">
      if valueXML.children.count >= 2 {
        let shadowBlockXML = valueXML.children[1]
        XCTAssertEqual("shadow", shadowBlockXML.name)
        XCTAssertEqual(2, shadowBlockXML.attributes.count)
        XCTAssertEqual("SHADOW_VALUE1", shadowBlockXML.attributes["id"])
        XCTAssertEqual("simple_input_output", shadowBlockXML.attributes["type"])
        XCTAssertEqual(1, shadowBlockXML.children.count)

        // Test: <value name="value">
        if shadowBlockXML.children.count >= 1 {
          let childValueXML = shadowBlockXML.children[0]
          XCTAssertEqual("value", childValueXML.name)
          XCTAssertEqual(1, childValueXML.attributes.count)
          XCTAssertEqual("value", childValueXML.attributes["name"])
          XCTAssertEqual(1, childValueXML.children.count)

          // Test: <shadow id="SHADOW_VALUE2" type="output_foo" />
          if childValueXML.children.count >= 2 {
            let childShadowBlockXML = childValueXML.children[1]
            XCTAssertEqual("shadow", childShadowBlockXML.name)
            XCTAssertEqual(2, childShadowBlockXML.attributes.count)
            XCTAssertEqual("SHADOW_VALUE2", childShadowBlockXML.attributes["id"])
            XCTAssertEqual("output_foo", childShadowBlockXML.attributes["type"])
            XCTAssertEqual(0, childShadowBlockXML.children.count)
          }
        }
      }
    }

    if xml.children.count >= 2 {
      // Test: <next>
      let nextXML = xml.children[1]
      XCTAssertEqual("next", nextXML.name)
      XCTAssertEqual(0, nextXML.attributes.count)
      XCTAssertEqual(1, nextXML.children.count)

      // Test: <shadow id="SHADOW_STATEMENT1" type="statement_no_input">
      if nextXML.children.count >= 1 {
        let shadowBlockXML = nextXML.children[0]
        XCTAssertEqual("shadow", shadowBlockXML.name)
        XCTAssertEqual(2, shadowBlockXML.attributes.count)
        XCTAssertEqual("SHADOW_STATEMENT1", shadowBlockXML.attributes["id"])
        XCTAssertEqual("statement_no_input", shadowBlockXML.attributes["type"])
        XCTAssertEqual(1, shadowBlockXML.children.count)

        // Test: <next>
        if shadowBlockXML.children.count >= 1 {
          let childNextXML = shadowBlockXML.children[0]
          XCTAssertEqual("next", childNextXML.name)
          XCTAssertEqual(0, childNextXML.attributes.count)
          XCTAssertEqual(1, childNextXML.children.count)

          // Test: <shadow id="SHADOW_STATEMENT2" type="statement_no_next" />
          if childNextXML.children.count >= 2 {
            let childShadowBlockXML = childNextXML.children[1]
            XCTAssertEqual("shadow", childShadowBlockXML.name)
            XCTAssertEqual(2, childShadowBlockXML.attributes.count)
            XCTAssertEqual("SHADOW_STATEMENT2", childShadowBlockXML.attributes["id"])
            XCTAssertEqual("statement_no_next", childShadowBlockXML.attributes["type"])
            XCTAssertEqual(0, childShadowBlockXML.children.count)
          }
        }
      }
    }
  }

  func testSerializeXML_BlockWithMutator() {
    // Add DummyMutator to "empty_block" factory builder
    factory.blockBuilder(forName: "empty_block")?.extensions = [BlockExtensionClosure { block in
      self.BKYAssertDoesNotThrow {
        try block.setMutator(DummyMutator())
      }
    }]

    guard let block = BKYAssertDoesNotThrow({
      try factory.makeBlock(name: "empty_block", shadow: false, uuid: "block_uuid")
    }) else {
      XCTFail("Could not create block")
      return
    }

    (block.mutator as? DummyMutator)?.id = "a_dummy_mutator_id"

    // This is the xml we expect from `block`:
    // <block type=\"empty_block\" id=\"block_uuid\" x=\"0\" y=\"0\" >
    //   <mutation id=\"a_dummy_mutator_id\" />
    // </block>
    guard let xml = BKYAssertDoesNotThrow({ try block.toXMLElement() }) else {
      XCTFail("Could not serialize block into XML")
      return
    }

    XCTAssertEqual("block", xml.name)
    XCTAssertEqual(4, xml.attributes.count)
    XCTAssertEqual("block_uuid", xml.attributes["id"])
    XCTAssertEqual("0", xml.attributes["x"])
    XCTAssertEqual("0", xml.attributes["y"])
    XCTAssertEqual("empty_block", xml.attributes["type"])
    XCTAssertEqual(1, xml.children.count)

    // Test: <mutation id=\"dummy_mutator_xml_id\" />
    if xml.children.count > 0 {
      let mutationXML = xml.children[0]
      XCTAssertEqual("mutation", mutationXML.name)
      XCTAssertEqual(1, mutationXML.attributes.count)
      XCTAssertEqual("a_dummy_mutator_id", mutationXML.attributes["id"])
      XCTAssertEqual(0, mutationXML.children.count)
    }
  }

  func testParseXML_BlockUndeletable() throws {
    let block = try factory.makeBlock(name: "empty_block", shadow: false)
    block.deletable = false

    // This is the xml we expect from `block`:
    // <block type=\"empty_block\" deletable=\"false\" />
    let xml = try block.toXMLElement()
    XCTAssertEqual("block", xml.name)
    XCTAssertTrue(xml.attributes.count >= 2)
    XCTAssertEqual("empty_block", xml.attributes["type"])
    XCTAssertEqual("false", xml.attributes["deletable"])
    XCTAssertEqual(0, xml.children.count)
  }

  func testParseXML_BlockImmovable() throws {
    let block = try factory.makeBlock(name: "empty_block", shadow: false)
    block.movable = false

    // This is the xml we expect from `block`:
    // <block type=\"empty_block\" movable=\"false\" />
    let xml = try block.toXMLElement()
    XCTAssertEqual("block", xml.name)
    XCTAssertTrue(xml.attributes.count >= 2)
    XCTAssertEqual("empty_block", xml.attributes["type"])
    XCTAssertEqual("false", xml.attributes["movable"])
    XCTAssertEqual(0, xml.children.count)
  }

  func testParseXML_BlockUneditable() throws {
    let block = try factory.makeBlock(name: "empty_block", shadow: false)
    block.editable = false

    // This is the xml we expect from `block`:
    // <block type=\"empty_block\" movable=\"false\" />
    let xml = try block.toXMLElement()
    XCTAssertEqual("block", xml.name)
    XCTAssertTrue(xml.attributes.count >= 2)
    XCTAssertEqual("empty_block", xml.attributes["type"])
    XCTAssertEqual("false", xml.attributes["editable"])
    XCTAssertEqual(0, xml.children.count)
  }

  func testParseXML_BlockDisabled() throws {
    let block = try factory.makeBlock(name: "empty_block", shadow: false)
    block.disabled = true

    // This is the xml we expect from `block`:
    // <block type=\"empty_block\" disabled=\"true\" />
    let xml = try block.toXMLElement()
    XCTAssertEqual("block", xml.name)
    XCTAssertTrue(xml.attributes.count >= 2)
    XCTAssertEqual("empty_block", xml.attributes["type"])
    XCTAssertEqual("true", xml.attributes["disabled"])
    XCTAssertEqual(0, xml.children.count)
  }

  func testParseXML_InputsInlineSame() throws {
    let builder = BlockBuilder(name: "empty_block")
    builder.inputsInline = false

    let block = try builder.makeBlock()

    // 'inline' should not appear as an attribute here, because it did not differ after block
    // creation.

    // This is the xml we expect from `block`:
    // <block type=\"empty_block\" />
    let xml = try block.toXMLElement()
    XCTAssertEqual("block", xml.name)
    XCTAssertTrue(xml.attributes.count >= 1)
    XCTAssertEqual("empty_block", xml.attributes["type"])
    XCTAssertNil(xml.attributes["inline"])
    XCTAssertEqual(0, xml.children.count)
  }

  func testParseXML_InputsInlineDifferent1() throws {
    let builder = BlockBuilder(name: "empty_block")
    builder.inputsInline = false

    let block = try builder.makeBlock()
    block.inputsInline = true

    // This is the xml we expect from `block`:
    // <block type=\"empty_block\" inline=\"true\" />
    let xml = try block.toXMLElement()
    XCTAssertEqual("block", xml.name)
    XCTAssertTrue(xml.attributes.count >= 2)
    XCTAssertEqual("empty_block", xml.attributes["type"])
    XCTAssertEqual("true", xml.attributes["inline"])
    XCTAssertEqual(0, xml.children.count)
  }

  func testParseXML_InputsInlineDifferent2() throws {
    let builder = BlockBuilder(name: "empty_block")
    builder.inputsInline = true

    let block = try builder.makeBlock()
    block.inputsInline = false

    // This is the xml we expect from `block`:
    // <block type=\"empty_block\" inline=\"false\" />
    let xml = try block.toXMLElement()
    XCTAssertEqual("block", xml.name)
    XCTAssertTrue(xml.attributes.count >= 2)
    XCTAssertEqual("empty_block", xml.attributes["type"])
    XCTAssertEqual("false", xml.attributes["inline"])
    XCTAssertEqual(0, xml.children.count)
  }

  // MARK: - Helper methods

  func parseBlockFromXML(_ xmlString: String, _ factory: BlockFactory) -> Block.BlockTree? {
    do {
      let xmlDoc = try AEXMLDocument(xml: xmlString)
      return try Block.blockTree(fromXML: xmlDoc.root, factory: factory)
    } catch {
    }

    return nil
  }
}
